﻿#region License
// /* **************************************************************
// * Copyright (C) intex Consulting GmbH - All Rights Reserved    *
// *--------------------------------------------------------------*
// * Unauthorized copying of this file, via any medium is         *
// * strictly prohibited                                          *
// *--------------------------------------------------------------*
// * Proprietary and confidential                                 *
// *--------------------------------------------------------------*
// * Dissasembling/modifications strictly prohibited!             *
// ***************************************************************/
#endregion

using System.Collections.Generic;
using System.Linq;
using System.Text;
using ComHlp.ContentClasses;
using ComHlp.ContentClasses.VirtualControls.ProgramExplorer;
using NLog;

namespace ComHlp.Classes.Parser.Supplementary
{
    internal static class AddonsParser
    {
        private static readonly Logger Log = LogManager.GetCurrentClassLogger();

        /// <summary> Parse Z001 / license information protocol response
        /// Filler		    X(10)
        /// Lizenzen		9(10)	vom eigenen Lizenztyp           
        /// LizTyp          X(04)
        /// Ges-Lizenzen	9(10)	über alle Typen
        /// </summary>
        /// <param name="licenseInformationStr"></param>
        public static ItxLicenseInformation ParseLicenseInfo(string licenseInformationStr)
        {
            if (licenseInformationStr.Length < 34)
                return null;

            ItxLicenseInformation licenseInformation = new ItxLicenseInformation
                {
                    FullLicenseCount = ParseHelper.String2Int(licenseInformationStr.Substring(10, 10)),
                    OverallLicenseCount = ParseHelper.String2Int(licenseInformationStr.Substring(24, 10))
                };
            return licenseInformation;
        }

        /// <summary> Parse Z002 / version information protocol resposne
        /// Version		X(04)
        /// Patch		9(02)
        /// Filler X(10)            sind 9.........
        /// NLS-Lang X(40)
        /// ServicePack	9(02)
        /// f.x. [5.0 3094389439 german_germany.we8pc850                 00]
        /// </summary>
        /// <param name="versionInformationStr"></param>
        /// <returns></returns>
        public static ItxVersionInformation ParseVersionInfo(string versionInformationStr)
        {
            if (versionInformationStr.Length < 57)
                return null;

            // f.x. [5.0 3094389439 german_germany.we8pc850                 00]
            ItxVersionInformation versionInformation = new ItxVersionInformation
                {
                    Version = versionInformationStr.Substring(0, 4).Trim(),
                    Patch = ParseHelper.String2Int(versionInformationStr.Substring(4, 2)),
                    NlsLang = versionInformationStr.Substring(15, 40).Trim(),
                    ServicePack = ParseHelper.String2Int(versionInformationStr.Substring(55, 2))
                };

            return versionInformation;
        }


        /// <summary> parse program explorer string </summary>
        /// <param name="programExplorerStr"></param>
        /// <param name="entries"></param>
        /// <returns>the next program to request</returns>
        public static string ParseProgramExplorerEntry(string programExplorerStr, List<ItxProgramExplorerEntry> entries)
        {
            /* we receive the following, where each 'entry' is 58 chars long:
             *  [AB01  NGM16  MAB01Auftragsbearbeitung                     ]
             *  [AB02  NAB01  GAB02Auftragsueberwachung Auswahl  ID        ]
             *  [AB03  NAB01  GAB03Auftragsueberwachung Anzeige  I         ]
             *  [AB04  NAB01  GAB04Auftrag Kopfdaten             VD        ]
             *  [AB05  NAB01  GAB05Auftrag Veredlung             V         ]
             *  [AB06  NAB01  GAB06sonstige Zu-/Abschlaege       V         ]
             *  [AB07  NAB01  GAB07Produktionspapiere Veredlung  D         ]
             *  [AB08  JAB01  GAB08Reservierung                  V         ]
             *  [AB09  NAB01  GAB09Info Auftragsstatus           V         ]
             *  [AB10  NAB01  GAB10Grob-Terminierung             V         ]
             *  
             * yes - we again have something special - alkdjfl;kajdsflk;jsadf
             *  [KD70  EKD01  GKD70Kundenstamminfo                         ]
             *  [KD70  Ew:\tools\Crv\crv w:\tools\crv\rpt\kd71.zahlungsbedi]
             *  [KD70  Ehlungsbedingungen dent intex   intex               ]
             * 
             */
            StringBuilder sbExplorerString = new StringBuilder(programExplorerStr);
            
            // parse all entries received
            while (sbExplorerString.Length > 58)
            {
                string program = sbExplorerString.ToString(0, 6).TrimEnd();
                // no program received? -> final end
                if (program.Length == 0 || program[0] == ' ')
                    return null;

                /* program already received? then we receive such kind of addition
                 * for external program start */
                var existingEntry = entries.FirstOrDefault(x => x.Program == program);
                if (existingEntry != null)
                {
                    sbExplorerString.Remove(0, 7);

                    string externalProgram;
                    if (ComStatics.UseUtf8)
                        externalProgram = ParseHelper.ExtractUtf8(41, sbExplorerString, true);
                    else
                    {
                        externalProgram = sbExplorerString.ToString(0, 41);
                        sbExplorerString.Remove(0, 41);
                    }
                    // the additional string starts after program + program iedntifier and has got an E for external
                    existingEntry.ExternalProgramHint = $"{existingEntry.ExternalProgramHint}{externalProgram}";
                    sbExplorerString.Remove(0, 10);
                    continue;
                }

                ItxProgramExplorerEntry entry = new ItxProgramExplorerEntry
                    {
                        Program = program,
                        Menue = sbExplorerString.ToString(7, 6).TrimEnd(),
                        FunctionCode = $"{sbExplorerString.ToString(14, 2).TrimEnd()}{sbExplorerString.ToString(16, 2).TrimEnd()}"
                    };

                // check program identifier
                char pIdentifier = sbExplorerString[6];
                switch (pIdentifier)
                {
                    case 'J':
                        entry.ProgramIdentifier = EProgramExplorerProgramType.NoDisplay;
                        break;
                    case 'N':
                        entry.ProgramIdentifier = EProgramExplorerProgramType.Display;
                        break;
                    case 'E':
                        entry.ProgramIdentifier = EProgramExplorerProgramType.ExternalCommand;
                        break;
                    default:
#if DEBUG
                        Log.Debug($"Unknown program explorer program identifier/type: {pIdentifier}");
#endif
                        break;
                }

                char mIdentifier = sbExplorerString[13];
                switch (mIdentifier)
                {
                    case 'M':
                        entry.MenuIdentifier = EProgramExplorerMenuType.Menu;
                        break;
                    case 'G':
                        entry.MenuIdentifier = EProgramExplorerMenuType.Normal;
                        break;
                    default:
#if DEBUG
                        Log.Debug($"Unknown program explorer menu identifier/type: {mIdentifier}");
#endif
                        break;
                }

                // cut and parse description
                sbExplorerString.Remove(0, 18);
                string description;
                if (ComStatics.UseUtf8)
                    description = ParseHelper.ExtractUtf8(30, sbExplorerString, true);
                else
                {
                    description = sbExplorerString.ToString(0, 30);
                    sbExplorerString.Remove(0, 30);
                }

                entry.Description = description.TrimEnd();
                entry.DisplayDescription = $"[{entry.Program}] {entry.Description}";

                // remove reserve + icon
                entry.Icon = sbExplorerString.ToString(0, 2);
                sbExplorerString.Remove(0, 10);
                entries.Add(entry);
            }

            // have we got some string length left? if yes, the first 6 bytes are the next to retrieve
            if (sbExplorerString.Length >= 6)
                return sbExplorerString.ToString(0, 6);

            // if not - return the last parsed program
            return entries[entries.Count].Program;
        }

        /// <summary> parse the favorites of program explorer </summary>
        /// <param name="favoriteStr"></param>
        /// <param name="favorites"></param>
        /// <returns></returns>
        public static string ParseFavorite(string favoriteStr, List<ItxFavorite> favorites)
        {
            /*  X(122)		Bereich zum Weiterlesen (space nach Userwechsel)
             *  70x
             *  -x(08)		eine Nummer; wichtig bei Änderungen etc.
             *  -x(30)		Bez (bei Menue)
             *  -9(01)		Stufe (beginnt bei 2, da „Favoriten“ = Stufe 1)
             *  -x(01)		Typ - G=Menue,E=externes Prog,I=Intex-Prog
             *  x(064)			Aktion bzw. Bez (wenn Bez leer)
             *  x(2)		Icon
             *  x(30)		reserver
             *  sample:
             *  [02        0011000000100000                                                                                                ]
             *  [00000001                              2IAB05                                                                                            ]
             *  [00000002                              2ICP02                                                                                            ]
             *  [00000003                              2IAE02                                                                                            ]
             *  [00000010                              2ICP01]
             */
            StringBuilder sbFavoriteString = new StringBuilder(favoriteStr);
            
            // at first - get the data for resetup if we have more than 70 favorites
            string reReadArea = sbFavoriteString.ToString(0, 122);
            sbFavoriteString.Remove(0, 122);

            // parse all entries received
            while (sbFavoriteString.Length > 136)
            {
                ItxFavorite favorite = new ItxFavorite
                    {
                        FavoriteNumber = ParseHelper.String2Int(sbFavoriteString.ToString(0, 8))
                    };
                if (favorite.FavoriteNumber == 0)
                    break;
                
                favorite.MenuDescription = sbFavoriteString.ToString(8, 30).TrimEnd();
                favorite.DisplayLevel = ParseHelper.String2Int(sbFavoriteString.ToString(38,1));
                switch (sbFavoriteString[39])
                {
                    case 'G':
                        favorite.Type = EProgramFavoriteType.Menu;
                        break;
                    case 'E':
                        favorite.Type = EProgramFavoriteType.ExternalProgram;
                        break;
                    case 'I':
                        favorite.Type = EProgramFavoriteType.IntexProgram;
                        break;
                    default:
#if DEBUG
                        Log.Warn($"Invalid favorite type: {sbFavoriteString[39]}!");
#endif
                        return "";
                }

                // the last part must not be completly filled, it can directly end after the respective part
                sbFavoriteString.Remove(0, 40);
                int cutLength = sbFavoriteString.Length > 64 ? 64 : sbFavoriteString.Length;
                favorite.Action = sbFavoriteString.ToString(0, cutLength).TrimEnd();
                sbFavoriteString.Remove(0, cutLength);

                // still got some space left? then we need to cut the reservation and not used icon
                if (sbFavoriteString.Length > 0)
                    sbFavoriteString.Remove(0, 32);

                // ANYthing usefull?
                if(string.IsNullOrEmpty(favorite.Action) && string.IsNullOrEmpty(favorite.MenuDescription))
                    continue;

                favorites.Add(favorite);
            }

            // request more?
            return favorites.Count % 70 == 0 ? reReadArea : "";
        }

        /// <summary> reorder the program explorer, eliminating every program which is not assigned to gm01 </summary>
        /// <param name="entries"></param>
        public static void ReOrderProgramExplorer(List<ItxProgramExplorerEntry> entries)
        {
            // remove all not displayed entries
            entries.RemoveAll(x => x.ProgramIdentifier == EProgramExplorerProgramType.NoDisplay);

            // at first, set gm01 linked
            var gm02Entry = entries.FirstOrDefault(x => x.Program == "GM02");
            if (gm02Entry == null)
                return;
            gm02Entry.Gm02Linked = true;

            // now parse forward starting from all programs which are linked to gm01
            foreach (var entry in entries.Where(x => x.Gm02Linked == false && x.Menue == "GM02"))
            {
                entry.Gm02Linked = true;

                // subiterate - maximum of 5 for not loosing ourself
                foreach (var subEntry1 in entries.Where(x => x.Gm02Linked == false && x.Menue == entry.Program))
                {
                    subEntry1.Gm02Linked = true;
                    foreach (var subEntry2 in entries.Where(x => x.Gm02Linked == false && x.Menue == subEntry1.Program))
                    {
                        subEntry2.Gm02Linked = true;
                        foreach (var subEntry3 in entries.Where(x => x.Gm02Linked == false && x.Menue == subEntry2.Program))
                        {
                            subEntry3.Gm02Linked = true;
                            foreach (var subEntry4 in entries.Where(x => x.Gm02Linked == false && x.Menue == subEntry3.Program))
                            {
                                subEntry4.Gm02Linked = true;
                                foreach (var subEntry5 in entries.Where(x => x.Gm02Linked == false && x.Menue == subEntry4.Program))
                                    subEntry5.Gm02Linked = true;
                            }
                        }
                    }
                }
            }

            // remove all unlinked
            entries.RemoveAll(x => x.Gm02Linked == false);

            // finished! \o/
        }
    }
}